Skip to content

Add moving-boundary solver support#53

Merged
jcschaff merged 3 commits into
mainfrom
moving-boundary-solver
Jun 24, 2026
Merged

Add moving-boundary solver support#53
jcschaff merged 3 commits into
mainfrom
moving-boundary-solver

Conversation

@jcschaff

Copy link
Copy Markdown
Member

Author and run VCell moving-boundary simulations from pyvcell, via libvcell (≥ 0.0.16) and the pyvcell-mbsolver package.

Authoring API (models_app)

  • Application.add_moving_boundary_sim(...) — a simulation with Solver="MovingB" and MovingBoundarySolverOptions.
  • Application.set_moving_boundary_front(velocity_x, velocity_y, ...) — the prescribed front velocity (FrontVelocity → a SurfaceKinematics process).
  • Simulation.solver / .moving_boundary_options / .is_moving_boundary.

The writer and (lenient) reader round-trip the Solver attribute and the MovingBoundarySolverOptions block.

Runtime

  • vc.simulate_moving_boundary(biomodel, sim) drives the pipeline:
    1. to_vcml_str (round-trip 1 → VCell computes geometry regions and auto-generates the canonical SpatialObjects)
    2. enable SurfaceVelocity + inject the SurfaceKinematics front velocity
    3. vcml_to_vcml (round-trip 2 → moving-boundary math: a MembraneSubDomain with a velocity)
    4. vcml_to_moving_boundary_inputMovingBoundarySetup XML → run pyvcell_mbsolver
  • Output is collected through the solver's observer callbacks (the binding writes no HDF5 file) into a new MovingBoundaryResult: per output time, the moving-front polygon plus per-element (x, y, grid_i, grid_j, concentration) on the moving mesh — mirroring vcell-core's element/species model rather than the fixed-grid zarr Result. Snapshots are subsampled to output_time_step.

Packaging

  • New mb optional extra (pyvcell-mbsolver, gated to Python < 3.14 since there is no cp314 wheel), added to all.
  • Lazy imports with a clear install pyvcell[mb] hint; validation errors surface without the solver extras installed.
  • A pyvcell_mbsolver mypy override + one # type: ignore[misc] cover the current 1.0.0 wheel which lacks py.typed; both can be removed once a typed wheel is published.

⚠️ Hold release until libvcell 0.0.16 is on PyPI

Authoring moving-boundary input requires libvcell ≥ 0.0.16, which is not yet published (latest on PyPI is 0.0.15.4). The native extra is intentionally held at >=0.0.15.3 and the requirement is documented. The PR can merge, but a release should wait for 0.0.16.

Verification

  • make check clean: uv lock --check, ruff, ruff-format, mypy (strict), deptry.
  • pytest: 111 passed, 11 skipped, including a gated end-to-end moving-boundary solve (a circular front under sin(t)/cos(t): 11 output frames, moving front, per-element concentrations). The end-to-end test skips automatically when libvcell < 0.0.16 or pyvcell-mbsolver is unavailable.

🤖 Generated with Claude Code

jcschaff and others added 2 commits June 24, 2026 01:08
Author and run VCell moving-boundary simulations from pyvcell via libvcell
(>= 0.0.16) and the pyvcell-mbsolver package.

Authoring API (models_app):
- Application.add_moving_boundary_sim(): a simulation with Solver="MovingB"
  and MovingBoundarySolverOptions.
- Application.set_moving_boundary_front(): the prescribed front velocity
  (FrontVelocity / SurfaceKinematics).
- Simulation.solver / .moving_boundary_options / .is_moving_boundary.

Writer/reader round-trip the Solver attribute and MovingBoundarySolverOptions.

Runtime:
- vc.simulate_moving_boundary(biomodel, sim) drives the pipeline:
  to_vcml_str (round-trip 1 -> VCell auto-generates SpatialObjects) ->
  inject SurfaceKinematics front velocity -> vcml_to_vcml (round-trip 2 ->
  moving-boundary math) -> vcml_to_moving_boundary_input -> run pyvcell_mbsolver.
- Output is collected via solver observers (no HDF5 file is written by the
  binding) into MovingBoundaryResult: per output time, the moving front polygon
  plus per-element (x, y, grid_i, grid_j, concentration) on the moving mesh,
  subsampled to output_time_step.

Packaging: new `mb` extra (pyvcell-mbsolver, gated to Python < 3.14), added to
`all`; lazy imports with a clear "install pyvcell[mb]" hint. The `native` extra
is held at >=0.0.15.3 until libvcell 0.0.16 is published to PyPI, so a release
should wait for that even though the PR can merge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
pyvcell-mbsolver 1.0.1 ships a py.typed marker, so the package now type-checks
natively. Bump the `mb` extra pin to >=1.0.1 and remove the workarounds that
covered the untyped 1.0.0 wheel:
- the [[tool.mypy.overrides]] for pyvcell_mbsolver
- the `# type: ignore[misc]` on class _Collector(mb.SimulationObserver)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jcschaff jcschaff marked this pull request as ready for review June 24, 2026 11:44
Both moving-boundary dependencies now ship Python 3.14-compatible wheels:
- libvcell 0.0.17 publishes universal py3-none-<platform> wheels (installable on
  every Python including 3.14) and includes moving-boundary support, so `native`
  requires >=0.0.17 and the code calls vcml_to_moving_boundary_input directly.
- pyvcell-mbsolver 1.0.3 adds cp314 wheels and _core.pyi stubs, so the `mb` extra
  drops its temporary `python_version < '3.14'` gate and requires >=1.0.3.

With both packages present and typed on all CI Python versions, the temporary
mypy workarounds (pyvcell_mbsolver ignore_missing_imports + disallow_subclassing_any)
are removed; mypy passes natively.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jcschaff jcschaff merged commit e6ff3be into main Jun 24, 2026
5 checks passed
@jcschaff jcschaff deleted the moving-boundary-solver branch June 24, 2026 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant